

local assert     = assert
local require    = require
local bit        = bit
local coroutine  = coroutine
local debug      = debug
local io         = io
local pairs      = pairs
local ipairs     = ipairs
local math       = math
local os         = os
local print      = print
local pcall      = pcall
local xpcall     = xpcall
local rawget     = rawget
local rawset     = rawset
local select     = select
local string     = string
local table      = table
local tonumber   = tonumber
local tostring	 = tostring
local error      = error
local type       = type
local unpack     = unpack
local setmetatable = setmetatable
local getmetatable = getmetatable
local ngx = ngx


local string_char  = string.char
local string_sub   = string.sub
local string_byte  = string.byte
local string_gsub  = string.gsub
local string_find  = string.find
local string_upper = string.upper

local math_fmod   = math.fmod
local math_floor  = math.floor
local math_pow    = math.pow


----数据变量----
local uu         = require("modules.commhm.utils")
local log        = require("modules.commhm.log")
local ns_time    = require("modules.commhm.time")
local ns_env     = require("modules.env.env")
local ns_auth_comm_checker = require("modules.commhm.auth_comm_checker")


local Log = log.debug;

local FOO = {
	_VERSION = '0.12.1',

	normal_exit = nil;
	error_exit  = nil;

};


-------------------------------------S7
FOO.ns_http_sec = ns_auth_comm_checker.ns_http_sec


-- 检查uin合法性
FOO.check_uin = function( uin_ )
	local uin = tonumber( uin_ ) or 0;
	if  uin < 1000 then
		FOO.error_exit( "auth_fail" );
	end
	ngx.ctx.m_params.uin = uin;
end


-- 检查uin合法性 不退出
FOO.check_uin_safe = function( uin_ )
	local uin = tonumber( uin_ ) or 0;
	if  uin < 1000 then
		log.error( "uin error=" .. (uin_ or 'nil') );
		return false
	end
	ngx.ctx.m_params.uin = uin;
	return true
end




--设置出错回调
FOO.set_error_exit = function( normal_exit_, error_exit_ )
	log.debug( "call set_error_exit" );
	if  FOO.error_exit then
		--已经设置
	else
		FOO.normal_exit = normal_exit_;
		FOO.error_exit  = error_exit_;
	end
end



--按照uin和参数time获得s2 salt
FOO.genS2Salt = ns_auth_comm_checker.genS2Salt


-- 检查合法性，但是不退出
FOO.check_act_auth_no_exit = function()
	local time_ = tonumber(ngx.ctx.m_params.time or 0) or 0;
	if  time_ <= 0 then
		return 1
	end

	local uin_ = tonumber( ngx.ctx.m_params.uin or 0 ) or 0;
	if  uin_ and uin_ >= 1000 then
		--normal
	else
		return 2
	end

	--auth
	if  ngx.ctx.m_params.auth then
		local auth_ = ngx.md5 ( time_ .. FOO.genS2Salt() .. uin_ );
		if  auth_ == ngx.ctx.m_params.auth then
			return 0  			--normal
		end
	end

	return 3
end



-- 检查act合法性
FOO.check_act_auth = function()

	--time
	local time_ = tonumber(ngx.ctx.m_params.time or 0) or 0;
	if  time_ <= 0 then
		--未设置时间点
		ngx.say( "error:auth_no_time" );
		FOO.error_exit( "error:auth_no_time" );
	end

	--uin
	local uin_ = tonumber( ngx.ctx.m_params.uin or 0 );
	if  uin_ and uin_ >= 1000 then
		--normal
	else
		if uin_ <= 1 then
			log.day( "error", "uin=" .. uin_ );
			FOO.normal_exit( "uin=" .. uin_ );
		else
			ngx.say( "error:auth_uin_fail." );
			FOO.error_exit( "error:auth_uin_fail." );
		end
	end

	ngx.ctx.m_params.uin = uin_;

	--auth
	if  ngx.ctx.m_params.auth then
		--log.debug( time_ .. '#auth#' .. uin_ );
		local auth_ = ngx.md5 ( time_ .. FOO.genS2Salt() .. uin_ );
		if  auth_ == ngx.ctx.m_params.auth then
			--normal
			log.debug( "check_act_auth ok, auth_=" .. auth_ );

			--if  ngx.ctx.m_params.s2t then
				--log.day_list("auth", "md5_ok", ngx.ctx.m_params.uin, ngx.ctx.m_params.apiid, ngx.ctx.m_params.act, (ngx.ctx.m_params.s2t or 'no_s2t') );
			--end

		else

			log.day_list("auth", "md5_error", ngx.ctx.m_params.uin, ngx.ctx.m_params.apiid, ngx.ctx.m_params.act,
					(ngx.ctx.m_params.s2t or 'no_s2t'),
					(ngx.ctx.request_uri_s7 or 'nil') .. "|" .. (ngx.var.request_uri or 'nil') );

			--log.day( "error", "error:auth_fail|" .. uin_ );
			log.debug( "check_act_auth fail, auth_=" .. auth_ .. "/" .. ngx.ctx.m_params.auth );
			if  ns_env.auth_debug==1 and ngx.ctx.m_params.test=='1' then
				log.debug("error:auth_fail1. ignore debug.");
			elseif ngx.ctx.m_params.test=='1' and ngx.ctx.m_params.s2t=="1355475757" then
				log.debug("error:auth_fail2. ignore no debug.");
				log.day_list("s2t", "ignore", ngx.ctx.m_params.uin, ngx.ctx.m_params.apiid, ngx.ctx.m_params.act,
						(ngx.ctx.m_params.s2t or 'no_s2t'),
						(ngx.ctx.request_uri_s7 or 'nil') .. "|" .. (ngx.var.request_uri or 'nil') );
			else
				ngx.say( "error:auth_fail" );
				if  uin_ == 12345 then
					FOO.normal_exit( "error:auth_fail_12345" );
				else
					--FOO.error_exit( "error:auth_fail_" .. uin_ );
					FOO.normal_exit( "error:auth_fail_" .. uin_ );
				end
			end


		end

	else

		if  ns_env.auth_debug==1 and ngx.ctx.m_params.test=='1' then
			log.debug("error:no_auth. debug.");
		else
			ngx.say( "error:no_auth." );
			FOO.error_exit( "error:no_auth." );
		end

	end

end



--内网cmd验证
FOO.check_cmd_auth = function()
	--time
	local time_ = tonumber(ngx.ctx.m_params.time or 0);
	if  time_ <= 0 then
		--未设置时间点
		ngx.say( "error:auth_no_time" );
		FOO.error_exit( "error:auth_no_time" );
	end

	--uin
	local uin_ = tonumber( ngx.ctx.m_params.uin or 0 );
	if  uin_ and uin_ >= 1000 then
		--normal
	else
		ngx.say( "error:auth_uin_fail." );
		FOO.error_exit( "error:auth_uin_fail." );
	end

	ngx.ctx.m_params.uin = uin_;
	
	local token_ = ngx.ctx.m_params.token;
	local cmd_   = ngx.ctx.m_params.cmd;

	--cmd auth
	FOO.check_comm_inner_token( token_, uin_, time_, cmd_ );
end


--地图加精选特别GM版本
FOO.private_check_auth2 = function()
	log.debug( "call private_check_auth2" );
	local u_ = tonumber( ngx.ctx.m_params.uin ) or 0;
	if  ( (u_ >= 1000001000 and u_ < 1000005000) or ( u_>=1000 and u_ < 5000) ) and ngx.ctx.m_params.time and
			ngx.ctx.m_params.fn and ngx.ctx.m_params.uin and  ngx.ctx.m_params.auth2 then
		local a_ = ngx.md5( ngx.ctx.m_params.fn .. "#miniw_op_907#" .. ngx.ctx.m_params.time .. "#" .. ngx.ctx.m_params.uin );
		--log.debug(  ngx.ctx.m_params.auth2 .. "##" .. a_ );
		if ngx.ctx.m_params.auth2 == a_ then
			return;
		end
	end

	if  ns_env.auth_debug==1 and ngx.ctx.m_params.test=='1' then
		log.debug("error:no_auth. debug.");
	elseif  ngx.ctx.m_params.test=='1' and  ngx.ctx.m_params.cmd == 'set_map_comment_stat' then
		log.debug("error:set_map_comment_stat. ignore.");
	else
		ngx.say( "error:auth_uin_fail2." );
		FOO.error_exit( "error:auth_uin_fail2." );
	end
end



-----------------------------------------------------------
-- 检测两个token值是否一致，测试环境可以略过
FOO.private_check_token_eq = function( t1, t2 )
	if  t1 == t2 then
		--normal
	elseif  ns_env.auth_debug==1 and ngx.ctx.m_params.test=='1' then
		log.day( "error", "error_token1" );
		log.debug( "error_token1, debug." );
	else
		log.day( "error", "error_token2" );
		FOO.normal_exit(  "error_token2" );
	end
end


-- 检查 comm inner token的正确性
FOO.check_comm_inner_token = function( token_, uin_, time_, cmd_, ext_info_ )
	local  ret_ =  ns_auth_comm_checker.gen_comm_inner_token( uin_, time_, cmd_, ext_info_ );
	return FOO.private_check_token_eq(token_, ret_)
end


-------------------------------------------------upload
--上传文件结果 upload_end
FOO.gen_upload_ret_token = function( md5_, uin_, node_, dir_ )
	local  upload_token_ret_ = ngx.md5( md5_ .. "#miniw_907#" .. uin_ .. "#" .. node_ .. "#" .. dir_ );
	return upload_token_ret_;
end

FOO.check_upload_ret_token = function( token_, md5_, uin_, node_, dir_ )
	local  ret_ = FOO.gen_upload_ret_token( md5_, uin_, node_, dir_ );
	FOO.private_check_token_eq(token_, ret_);
end


---检查后不退出0=ok  others=fail
FOO.check_upload_ret_token_safe = function( token_, md5_, uin_, node_, dir_ )
	local  ret_ = FOO.gen_upload_ret_token( md5_, uin_, node_, dir_ );
	return ns_auth_comm_checker.private_check_token_eq_safe(token_, ret_)
end


--ma服的内部auth
FOO.gen_ma_inner_auth = function( time_, uin_ )
	local  auth_ = ngx.md5( time_ .. "#miniw_907#" .. uin_ );
	return auth_;
end


---------------------------------------upload
--移动(删除)map+thumb文件
FOO.gen_moving_map_authd = function( n1_, n2_, node_, dir_ )
	local  authd_ret_ =  ngx.md5 ( (n1_ or "") .. '#' .. (n2_ or "") .. '#10061006#' .. node_ .. '#_go_to_upload_#' .. dir_ );
	return authd_ret_;
end

FOO.check_moving_map_authd = function( authd_, n1_, n2_, node_, dir_ )
	local  ret_ =  FOO.gen_moving_map_authd( n1_, n2_, node_, dir_ );
	FOO.private_check_token_eq(authd_, ret_);
end


---------------------------------------upload
--upload_pre验证
FOO.gen_upload_pre_token = function( uin_, node_, dir_ )
	local  authd_ret_ =  ngx.md5( uin_ .. '#' .. node_ .. '#_go_to_upload_#' .. dir_ );
	return authd_ret_;
end

FOO.check_upload_pre_token = function( token_, uin_, node_, dir_  )
	local  ret_ =  FOO.gen_upload_pre_token( uin_, node_, dir_  );
	FOO.private_check_token_eq(token_, ret_);
end


--------------------------------------------
FOO.gen_posting_auth = function()
	return "a1234567890";
end

FOO.check_posting_auth = function( auth_ )
	local  ret_ =  FOO.gen_posting_auth();
	FOO.private_check_token_eq(auth_, ret_);
end


--检查内容的hash值
FOO.checkContentHash = function( uin_, time_, cthash_, all_txt_, where_ )
	local time_ = tonumber( time_ ) or 0
	local  string_ = ngx.md5( uin_ .. all_txt_ .. time_ )
	local  content_hash_ = string.sub( string_, 7, 16 )
	if  cthash_ == content_hash_ then
		log.day_list( "realNameMobile", where_, "checkContentHash_ok",    uin_, content_hash_, cthash_, uu.now() - time_ )
		return true
	else
		log.day_list( "realNameMobile", where_, "checkContentHash_error", uin_, content_hash_, cthash_, uu.now() - time_ )
		return true  --- 暂时不检测
	end
	return false
end



return FOO;
